﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common;
using Dal;
using System.Collections;
using ResultManagement;
using System.Timers;
using LuceneManager;

namespace Notifying
{
    public class NotifyEventArgs : EventArgs
    {
      
        public NotifyEventArgs(User user, List<Document> documents, string query)
        {
            User = user;
            Documents = documents;
            Query = query;

        }
        public User User; //The user to notify
        public List<Document> Documents; //The documents relevant to this user.
        public string Query;
    }

    public class Notifier
    {
        public event EventHandler<NotifyEventArgs> NotificationEvent;
        Emailer _emailer;
        int _interval;
        int _realTimeInterval;
        LuceneSettings _ls;
      
        Timer _notifyTimer;
        Timer _realTimeNotifyTimer;

        public int RealTimeInterval
        {
            get { return _realTimeInterval; }
            set { _realTimeInterval = value; }
        }
        public int Interval
        {
            get { return _interval; }
            set { _interval = value; }
        }

        public Notifier(int interval, int realTimeInterval, string prefixFilePath, 
            List<IndexNode> indexNodePaths)
        {
            _emailer = new Emailer("mailgw.netvision.net.il");
            _interval = interval;
            _ls = new LuceneSettings(indexNodePaths.ToArray(), prefixFilePath);
            _realTimeInterval = realTimeInterval;

        }

        public void StartNotificationTimers()
        {
            _notifyTimer = new Timer(CalculateTimerInterval(_interval));
            _notifyTimer.Elapsed += new ElapsedEventHandler(_notifyTimer_Elapsed);
            _notifyTimer.Start();
            _realTimeNotifyTimer = new Timer(CalculateTimerInterval(_realTimeInterval));
            _realTimeNotifyTimer.Elapsed += new ElapsedEventHandler(_realTimeNotifyTimer_Elapsed);
            _realTimeNotifyTimer.Start();
        }

        void _realTimeNotifyTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            NotifyUsersRealTime();
            _realTimeNotifyTimer.Interval = CalculateTimerInterval(_realTimeInterval);
        }

       
        void _notifyTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            NotifyUsersAtInterval();
            _notifyTimer.Interval = CalculateTimerInterval(_interval);
        }

        /// <summary>
        /// Notifies users of new search results.
        /// </summary>
        public void NotifyUsersAtInterval()
        {
            //Run all user queries using current catalog.
            QueryRunning.QueryRunner QueryRunner =
               new QueryRunning.QueryRunner(_ls);
            QueryRunner.RunAllUserQueries(DateTime.Now.Subtract(new TimeSpan(0,_interval,0)));
            //Notify all users.
            Dal.DatabaseAbstractionLayer dal = new DatabaseAbstractionLayer();
            List<User> Users = dal.GetUsers();
            foreach (User user in Users)
            {
                NotifyUserAllQueries(user, false);
            }
        }

        public void NotifyUsersRealTime()
        {
            QueryRunning.QueryRunner QueryRunner =
               new QueryRunning.QueryRunner(_ls);
            List<string> userNotifications =
                QueryRunner.RunAllUserQueries(DateTime.Now.Subtract
                (new TimeSpan(0, _realTimeInterval, 0)));
            foreach (string user in userNotifications)
            {
                NotifyUserAllQueries(user, true);
            }
        }

        int CalculateTimerInterval(int minute)
        {
            if (minute <= 0)
                minute = 60;
            DateTime now = DateTime.Now;
            DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
            TimeSpan interval = future - now;
            return (int)interval.TotalMilliseconds;
        }

        public bool ShouldUpdateNow(List<UpdateTime> updateTimes)
        {
            foreach (UpdateTime ut in updateTimes)
            {
                if (DateTime.Now.Hour == ut.Hour.TotalHours && DateTime.Now.DayOfWeek == ut.Day)
                    return true;
            }
            return false;
        }


        public void NotifyUserAllQueries(string userName, bool updateRealTime)
        {
            Dal.DatabaseAbstractionLayer dal = new DatabaseAbstractionLayer();
            NotifyUserAllQueries(dal.GetUserByUserName(userName), updateRealTime);
        }

        /// <summary>
        /// Notifies the user of results.
        /// </summary>
        /// <param name="User"></param>
        public void NotifyUserAllQueries(User user, bool updateRealTime) 
        {
            Hashtable DocQueries = new Hashtable(); 
            
            HebrewStemmer hs = new HebrewStemmer(_ls.PrefixFilePath);

            ResultManager rm = new ResultManager(_ls);

            foreach (Category Category in user.Categories)
            {
                //If this category's update time is now.
                if ((updateRealTime && Category.UpdateRealTime) || (!updateRealTime && ShouldUpdateNow(Category.UpdateTimes)))
                {
                    string EmailText = HTMLBuilder.BuildResultHTML_AllQueriesInDocument(
                        user, Document.SortDocumentsByPriorityDate(
                        rm.GetExcerpts(
                        rm.GetUserCategoryResults(user.UserName, Category, false),
                        Category.Queries, -1, -1)));
                    if (!(EmailText.Equals(string.Empty)))
                     _emailer.SendEmail(EmailText, user.Email);
                    //if (null != NotificationEvent)
                    // NotificationEvent(this, new NotifyEventArgs(user, results, uq.Text));
                }
            }
        }


    }
}
